package m.common.model.util;

import m.common.model.Model;
import m.common.model.TableMeta;
import m.common.model.config.ModelConfig;
import m.system.util.SystemUtil;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 视图解析工具   待解析格式  #{-----$(key)---}  #{}内是内容，$()是参数
 * sql中包含待解析字符 #{ and a.name=$(q_name) }  >> and a.name=? 和一个参数
 * 如果params不包含q_name，则#{****}串从sql中删除
 * 如果params中的q_name是数组，例：#{ and a.name in($(q_name)) }  >> and a.name in(?,?,?) 和三个参数
 * 如果解析字符中包含多个参数，那么params中也需要存在这几个参数，否则#{****}串从sql中删除
 */
public class ModelViewUtil {
    private final StringBuilder allSql;
    private final Map<String,Object> params;
    private QueryParameter queryParameter;

    /**
     * 用视图模型构建
     */
    public <T extends Model> ModelViewUtil(Class<T> clazz, Map<String,Object> params){
        this("",params);
        TableMeta tm= ModelConfig.getTableMeta(clazz);
        this.allSql.append(tm.viewSql()).append(" ");
    }
    /**
     * 用sql构建
     */
    public ModelViewUtil(String sql, Map<String,Object> params){
        this.allSql=new StringBuilder();
        this.allSql.append(sql).append(" ");
        this.params=new HashMap<>();
        this.params.putAll(params);
    }

    private String getParamSql(int n){
        StringBuilder sql=new StringBuilder();
        for(int i=0;i<n;i++){
            if(i!=0) sql.append(",");
            sql.append("?");
        }
        return sql.toString();
    }
    private Object[] getParamValue(String key){
        if(null!=this.params.get(key)){
            Object v=this.params.get(key);
            if(v instanceof Object[]){
                return (Object[]) v;
            }else if(v instanceof List){
                return ((List<?>)v).toArray();
            }else{
                return new Object[]{v};
            }
        }else{
            return null;
        }
    }

    /**转换子sql里的所有参数，并返回sql和参数
     */
    private Object[] convertParams(String subSql){
        Pattern npat=Pattern.compile("\\$\\(.+?\\)");
        Matcher nm=npat.matcher(subSql);
        boolean isRep=true;
        List<Object> ls=new ArrayList<>();
        while(nm.find()){
            String s=nm.group();
            String k=s.substring(2,s.length()-1);
            Object[] arr=getParamValue(k);
            if(null!=arr){
                subSql=subSql.replace(s,getParamSql(arr.length));
                ls.addAll(Arrays.asList(arr));
            }else isRep=false;
        }
        if(isRep){
            return new Object[]{subSql,ls.toArray(new Object[0])};
        }else{
            return new Object[]{"",new Object[0]};
        }
    }
    public QueryParameter getParameter(){
        if(null==this.queryParameter){
            String sql=this.allSql.toString();
            List<Object> paramList=new ArrayList<>();
            Pattern pattern=Pattern.compile("\\#\\{.+?\\}");
            Matcher matcher=pattern.matcher(sql);
            while(matcher.find()){
                String str=matcher.group();
                String subSql=str.substring(2,str.length()-1);
                Object[] ps=convertParams(subSql);//取子sql转换里面的参数
                sql=sql.replace(str,(String)ps[0]);
                paramList.addAll(Arrays.asList((Object[]) ps[1]));
            }
            this.queryParameter=new QueryParameter(sql,paramList);
        }
        return this.queryParameter;
    }

    public static void main(String[] a){
        String sql="1234 #{ and a.name in($(q_name)) } 1111 #{ and a.value in($(q_value)) }2222" +
                "#{ and a.value in($(q_value)) and a.name in($(q_name)) }";
        Map<String,Object> params=new HashMap<>();
        params.put("q_name",new String[]{"1","2"});
        params.put("q_value",new String[]{"3","4"});
        QueryParameter qp=new ModelViewUtil(sql,params).getParameter();
        SystemUtil.println(qp.getSql());
        SystemUtil.println(qp.getValueList());
    }
}
